'''
Created on 2012-12-21

@author: levi
'''

import pydot
import datetime
from uuid import UUID

from core.himesis import HConstants as HC
from core.himesis import Himesis

from tc_python.arule import ARule
from tc_python.frule import FRule
from tc_python.lrule import LRule

from t_core.messages import Packet
from t_core.matcher import Matcher
from t_core.rewriter import Rewriter
from t_core.iterator import Iterator
from t_core.resolver import Resolver
from t_core.rollbacker import Rollbacker

from symbolic_state_space import SymbolicStateSpace

#from transformation_patterns.HS2S_clean import HS2S_clean
from transformation_patterns.HM2M import HM2M

from collapse_patterns_old.HTwoStations import HTwoStations
from collapse_patterns_old.HOneStation import HOneStation

from symbolic_exec_patterns.HBuild_backLHS import HBuild_backLHS
from symbolic_exec_patterns.HBuild_backRHS import HBuild_backRHS

from collapse_patterns.HFindTwoElementsSameTypeLHS import HFindTwoElementsSameTypeLHS

from collapse_patterns.HMoveOneInputMatchModelLHS import HMoveOneInputMatchModelLHS
from collapse_patterns.HMoveOneInputMatchModelRHS import HMoveOneInputMatchModelRHS
from collapse_patterns.HMoveOneInputApplyModelLHS import HMoveOneInputApplyModelLHS
from collapse_patterns.HMoveOneInputApplyModelRHS import HMoveOneInputApplyModelRHS
from collapse_patterns.HMoveOneInputDirectMatchLHS import HMoveOneInputDirectMatchLHS
from collapse_patterns.HMoveOneInputDirectMatchRHS import HMoveOneInputDirectMatchRHS
from collapse_patterns.HMoveOneInputDirectMatchLHS import HMoveOneInputDirectMatchLHS
from collapse_patterns.HMoveOneInputDirectMatchRHS import HMoveOneInputDirectMatchRHS
from collapse_patterns.HMoveOneOutputDirectMatchLHS import HMoveOneOutputDirectMatchLHS
from collapse_patterns.HMoveOneOutputDirectMatchRHS import HMoveOneOutputDirectMatchRHS
from collapse_patterns.HMoveOneInputIndirectMatchLHS import HMoveOneInputIndirectMatchLHS
from collapse_patterns.HMoveOneInputIndirectMatchRHS import HMoveOneInputIndirectMatchRHS
from collapse_patterns.HMoveOneOutputIndirectMatchLHS import HMoveOneOutputIndirectMatchLHS
from collapse_patterns.HMoveOneOutputIndirectMatchRHS import HMoveOneOutputIndirectMatchRHS
from collapse_patterns.HMoveOneInputDirectApplyLHS import HMoveOneInputDirectApplyLHS
from collapse_patterns.HMoveOneInputDirectApplyRHS import HMoveOneInputDirectApplyRHS
from collapse_patterns.HMoveOneOutputDirectApplyLHS import HMoveOneOutputDirectApplyLHS
from collapse_patterns.HMoveOneOutputDirectApplyRHS import HMoveOneOutputDirectApplyRHS
from collapse_patterns.HDeleteSecondCollapseElementMatchLHS import HDeleteSecondCollapseElementMatchLHS
from collapse_patterns.HDeleteSecondCollapseElementMatchRHS import HDeleteSecondCollapseElementMatchRHS
from collapse_patterns.HDeleteSecondCollapseElementApplyLHS import HDeleteSecondCollapseElementApplyLHS
from collapse_patterns.HDeleteSecondCollapseElementApplyRHS import HDeleteSecondCollapseElementApplyRHS

from collapse_patterns.HTestMatchLHS import HTestMatchLHS
from collapse_patterns.HTestMatchRHS import HTestMatchRHS

from collapse_patterns.HRuleExample import HRuleExample
from collapse_patterns.HRuleExampleDirect import HRuleExampleDirect
from collapse_patterns.HRuleExampleIndirect import HRuleExampleIndirect

from collapse_with_backward_patterns.HFindTwoMatchElementsWithBackwardLHS import HFindTwoMatchElementsWithBackwardLHS
from collapse_with_backward_patterns.HS2MS2Fexample import HS2MS2Fexample

from copy import deepcopy


def graph_to_dot(name, g):
    vattr=''
    eattr = ''
    nodes = {}
    graph = pydot.Dot(name, graph_type='digraph')
    dateTag = datetime.datetime.now().strftime("%Y-%b-%d_%H-%M-%S")
    for v in g.vs:
        vattr += str(v['name'])                                                                                                                                                                                     
        vattr += ' < '
        vattr += str(v['mm__']) 
        vattr += ' < '        
        vattr += str(v['GUID__'])[-12:]
        print vattr     
        nodes[v.index] = pydot.Node(vattr)
        graph.add_node(nodes[v.index])
        vattr = ''
    for e in g.es:
        graph.add_edge(pydot.Edge(nodes[e.source],nodes[e.target]))
#    graph.write('/home/levi/Desktop/STATE%s%s.svg'%(key,dateTag))    
    graph.write('/home/levi/Desktop/%s.dot'%name)
    
    
def merge_models(first, second):
    nb_nodes_first = len(first.vs)
    for index_v in range(len(second.vs)):
        first.add_node()
        first.vs[nb_nodes_first + index_v]['mm__'] = second.vs[index_v]['mm__']   
        first.vs[nb_nodes_first + index_v]['name'] = second.vs[index_v]['name'] 
    for index_e in range(len(second.es)):
        first.add_edges((nb_nodes_first + second.es[index_e].tuple[0],nb_nodes_first + second.es[index_e].tuple[1]))
    return first


def eliminate_repeated_collapse_matches(match_set):
    new_match_set = []
    for i in range(0, len(match_set)):
        found_repeated = False
        for j in range(0, i):
            if match_set[i]['1'] == match_set[j]['2'] and match_set[i]['2'] == match_set[j]['1']:
                found_repeated = True
                break
        if not found_repeated:
            new_match_set.append(match_set[i])
    return new_match_set

    
def collapse(p, index):
    
#    graph_to_dot('out' + str(index), p.graph)
    
    i = Iterator()
#    r = Rollbacker(HFindTwoStationsLHS())
    p = find_elements_collapse.packet_in(p)
    
#    print find_elements_collapse.is_success  

    if True:

#        print 'Before:'
#        print p.match_sets[p.current].matches
#        p.match_sets[p.current].matches = eliminate_repeated_collapse_matches(p.match_sets[p.current].matches)
#        print 'After:'
#        print p.match_sets[p.current].matches        
#        print '------------------------------------'     
        
        p = i.packet_in(p)     
#        p = r.packet_in(p)             

#        m = ARule(HTestMatchLHS(), HTestMatchRHS())
#        m = Matcher(HTestMatchLHS())

        while True:
            
#            print '-----> Depth: ' + str(index)
#            print p
#            print p.match_sets[p.current].match2rewrite
    
            # perform one collapse step

#            p = rin_match_direct.packet_in(p)

#            p = find_elements_collapse.packet_in(p)
            p = rin_match_direct.packet_in(p)
            p = rin_match_indirect.packet_in(p)
            p = rout_match_direct.packet_in(p)         
            p = rout_match_indirect.packet_in(p)
            p = erase_match_collapse_element.packet_in(p)
            
            print 'In:' + str(erase_match_collapse_element.is_success)
            
            print p
            
            graph_to_dot('out', p.graph)            
            
            break
            
#            p = rout_match_direct.packet_in(p)
#            p = erase_match.packet_in(p)    
#            
##            graph_to_dot('out' + str(index) + '.' + str(i.iterations), p.graph)
#            
#            p1 = Packet()
#            p1.graph = deepcopy(p.graph)
#            
#            # collapse the remaining graph   
#            collapse(p1, index+1)            
#    
#            # get back the graph previously to the collapse step
#            p = r.next_in(p)
#            # iterate to the next two elements to collapse
#            p = i.next_in(p)
#            if not i.is_success:
#                return True
#            
# #           print p
#
#            # save the state of the iterator before collapsing
#            p = r.packet_in(p)
        
    else:
        return False


def collapse_backward(p, index):
    
#    graph_to_dot('out' + str(index), p.graph)
    
    i = Iterator()
#    r = Rollbacker(HFindTwoStationsLHS())
    p = find_elements_collapse_backward.packet_in(p)          
    p = i.packet_in(p)    
    
    p = rin_match_direct.packet_in(p)
    p = rin_match_indirect.packet_in(p)
    p = rout_match_direct.packet_in(p)         
    p = rout_match_indirect.packet_in(p)

    print 'Result:' + str(erase_match_collapse_element.is_success)
    
    p = erase_match_collapse_element.packet_in(p)
    
 #   graph_to_dot('out', p.graph)


if __name__ == '__main__':                                                                                                                              
    pass

                                                                                                                                                                                   
find_elements_collapse = Matcher(HFindTwoElementsSameTypeLHS())

rin_matchmodel = ARule(HMoveOneInputMatchModelLHS(), HMoveOneInputMatchModelRHS())
rin_applymodel = FRule(HMoveOneInputApplyModelLHS(), HMoveOneInputApplyModelRHS())
rin_match_direct = FRule(HMoveOneInputDirectMatchLHS(), HMoveOneInputDirectMatchRHS())
rout_match_direct = FRule(HMoveOneOutputDirectMatchLHS(), HMoveOneOutputDirectMatchRHS())
rin_match_indirect = FRule(HMoveOneInputIndirectMatchLHS(), HMoveOneInputIndirectMatchRHS())
rout_match_indirect = FRule(HMoveOneOutputIndirectMatchLHS(), HMoveOneOutputIndirectMatchRHS())
rin_apply_direct = FRule(HMoveOneInputDirectApplyLHS(), HMoveOneInputDirectApplyRHS())
rout_apply_direct = FRule(HMoveOneOutputDirectApplyLHS(), HMoveOneOutputDirectApplyRHS())

erase_match_collapse_element = FRule(HDeleteSecondCollapseElementMatchLHS(), HDeleteSecondCollapseElementMatchRHS())
erase_apply_collapse_element = FRule(HDeleteSecondCollapseElementApplyLHS(), HDeleteSecondCollapseElementApplyRHS())

find_elements_collapse_backward = Matcher(HFindTwoMatchElementsWithBackwardLHS())

p = Packet()

p1 = Packet()

p.graph = HRuleExampleIndirect()

p1.graph = HS2MS2Fexample()

graph_to_dot('source', p1.graph)

#collapse(p, 1)

collapse_backward(p1, 1)

